===== src/useFormWithHooks.ts ================================ import { FormEvent, useState } from 'react'; export default function useApp() { const [count, setCount] = useState(0); const [name, setName] = useState(''); const [response, setResponse] = useState(null); const [waiting, setWaiting] = useState(false); const handleClicked = async (e: FormEvent) => { e.preventDefault(); //alert('clicked!'); setCount(count + 1); setWaiting(true); const response = await fetch( 'https://robsimmons-nameseeingserver.web.val.run', { method: 'POST', body: JSON.stringify({ key: 'abracadabra', name }), }, ); const { message } = await response.json(); setWaiting(false); setResponse(message); }; return { count, name, setName, waiting, response, handleClicked }; } ===== src/FormWithHooks.tsx ================================== import useFormWithHooks from './useFormWithHooks.ts'; export default function FormWithHooks() { const { count, name, setName, waiting, response, handleClicked } = useFormWithHooks(); return (
  1. First
  2. Second
  3. You clicked the button {count} times, {name}!
  4. {response &&
  5. {response}
  6. }
setName(e.target.value)} value={name} />
{waiting && "I'm waiting"}
); } ===== src/IdleGame.tsx ======================================= import { useEffect, useState } from 'react'; export default function IdleGame() { const [count, setCount] = useState(0); const [auto, setAuto] = useState(false); useEffect(() => { if (!auto) return; let timer: number; /** Clicks, waits one second, then calls itself */ function timedClick() { setCount(oldCount => oldCount + 1); timer = setTimeout(timedClick, 1000); } timer = setTimeout(timedClick, 1000); return () => { clearTimeout(timer); }; }, [auto]); return ( <>
  1. First
  2. Second
  3. You clicked the button {count} times!

); }